﻿namespace TfsReportRenderer.ImageAdder
{
    using System.Drawing;
    using System.Globalization;
    using System.IO;
    using System.Linq;

    using DocumentFormat.OpenXml;
    using DocumentFormat.OpenXml.Drawing;
    using DocumentFormat.OpenXml.Drawing.Spreadsheet;
    using DocumentFormat.OpenXml.Packaging;
    using DocumentFormat.OpenXml.Spreadsheet;

    using BlipFill = DocumentFormat.OpenXml.Drawing.Spreadsheet.BlipFill;
    using NonVisualDrawingProperties = DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualDrawingProperties;
    using NonVisualPictureDrawingProperties = DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualPictureDrawingProperties;
    using NonVisualPictureProperties = DocumentFormat.OpenXml.Drawing.Spreadsheet.NonVisualPictureProperties;
    using Path = System.IO.Path;
    using Position = DocumentFormat.OpenXml.Drawing.Spreadsheet.Position;
    using ShapeProperties = DocumentFormat.OpenXml.Drawing.Spreadsheet.ShapeProperties;

    public static class FormattingOpenXmlSpreadsheet
    {
        public static void InsertImage(Worksheet worksheet, long x, long y, long? width, long? height, string imagePath)
        {
            worksheet.MustNotBeNull("ws");
            imagePath.MustNotBeNull("sImagePath");

            WorksheetPart wsp = worksheet.WorksheetPart;
            DrawingsPart dp;
            ImagePart imgp;
            WorksheetDrawing wsd;

            ImagePartType ipt;
            var extension = Path.GetExtension(imagePath) ?? string.Empty;
            switch (extension.ToUpperInvariant())
            {
                case ".PNG":
                    ipt = ImagePartType.Png;
                    break;
                case ".JPG":
                case ".JPEG":
                    ipt = ImagePartType.Jpeg;
                    break;
                case ".GIF":
                    ipt = ImagePartType.Gif;
                    break;
                default:
                    return;
            }

            if (wsp.DrawingsPart == null)
            {
                // no drawing part exists, add a new one
                dp = wsp.AddNewPart<DrawingsPart>();
                imgp = dp.AddImagePart(ipt, wsp.GetIdOfPart(dp));
                wsd = new WorksheetDrawing();
            }
            else
            {
                // use existing drawing part
                dp = wsp.DrawingsPart;
                imgp = dp.AddImagePart(ipt);
                dp.CreateRelationshipToPart(imgp);
                wsd = dp.WorksheetDrawing;
            }

            using (FileStream fs = new FileStream(imagePath, FileMode.Open))
            {
                imgp.FeedData(fs);
            }

            int imageNumber = dp.ImageParts.Count<ImagePart>();
            if (imageNumber == 1)
            {
                worksheet.AppendChild(new Drawing { Id = dp.GetIdOfPart(imgp) });
            }

            var nvdp = new NonVisualDrawingProperties
                           {
                               Id = new UInt32Value((uint)(1024 + imageNumber)),
                               Name = "Picture " + imageNumber.ToString(CultureInfo.InvariantCulture),
                               Description = string.Empty
                           };

            var picLocks = new DocumentFormat.OpenXml.Drawing.PictureLocks { NoChangeAspect = true, NoChangeArrowheads = true };
            var nvpdp = new NonVisualPictureDrawingProperties { PictureLocks = picLocks };
            var nvpp = new NonVisualPictureProperties { NonVisualDrawingProperties = nvdp, NonVisualPictureDrawingProperties = nvpdp };

            var stretch = new DocumentFormat.OpenXml.Drawing.Stretch { FillRectangle = new DocumentFormat.OpenXml.Drawing.FillRectangle() };

            var blipFill = new BlipFill();
            var blip = new DocumentFormat.OpenXml.Drawing.Blip
                           {
                               Embed = dp.GetIdOfPart(imgp),
                               CompressionState = DocumentFormat.OpenXml.Drawing.BlipCompressionValues.Print
                           };

            blipFill.Blip = blip;
            blipFill.SourceRectangle = new DocumentFormat.OpenXml.Drawing.SourceRectangle();
            blipFill.AppendChild(stretch);

            var t2D = new DocumentFormat.OpenXml.Drawing.Transform2D();
            var offset = new DocumentFormat.OpenXml.Drawing.Offset { X = 0, Y = 0 };
            t2D.Offset = offset;
            Extents extents;
            using (var bm = new Bitmap(imagePath))
            {
                extents = new DocumentFormat.OpenXml.Drawing.Extents
                              {
                                  Cx = width ?? (long)bm.Width * (long)((float)914400 / bm.HorizontalResolution),
                                  Cy = height ?? (long)bm.Height * (long)((float)914400 / bm.VerticalResolution)
                              };

                t2D.Extents = extents;
            }

            var sp = new ShapeProperties { BlackWhiteMode = DocumentFormat.OpenXml.Drawing.BlackWhiteModeValues.Auto, Transform2D = t2D };
            var prstGeom = new DocumentFormat.OpenXml.Drawing.PresetGeometry
                               {
                                   Preset = DocumentFormat.OpenXml.Drawing.ShapeTypeValues.Rectangle,
                                   AdjustValueList = new DocumentFormat.OpenXml.Drawing.AdjustValueList()
                               };
            sp.AppendChild(prstGeom);
            sp.AppendChild(new DocumentFormat.OpenXml.Drawing.NoFill());

            var picture = new DocumentFormat.OpenXml.Drawing.Spreadsheet.Picture
                              {
                                  NonVisualPictureProperties = nvpp,
                                  BlipFill = blipFill,
                                  ShapeProperties = sp
                              };

            var pos = new Position { X = x, Y = y };
            var ext = new Extent { Cx = extents.Cx, Cy = extents.Cy };
            var anchor = new AbsoluteAnchor { Position = pos, Extent = ext };
            anchor.AppendChild(picture);
            anchor.AppendChild(new ClientData());
            wsd.AppendChild(anchor);
            wsd.Save(dp);
        }

        public static void InsertImage(Worksheet worksheet, long x, long y, string imagePath)
        {
            InsertImage(worksheet, x, y, null, null, imagePath);
        }
    }
}